// --------------------------------------------------------------------------
// XmlHandler.cpp
//
// Copyright 2007, Antony Pranata
// http://www.antonypranata.com
//
// Example how to parse XML file using SAX on Symbian OS.
//
// There are two methods to parse XML document, i.e.;
//   - StartParsingL() -> parse XML document without active object.
//     The whole file content is read at once. It is simple, but suitable
//     for relatively small file only.
//   - StartParsingWithAoL() -> parse XML document with active object.
// --------------------------------------------------------------------------

// INCLUDE FILES
#include <coemain.h>
#include <f32file.h>
#include "XmlHandler.h"
#include "XmlNode.h"

#ifdef __WINSCW__
#include <e32svr.h>   //RDebug
#endif

// CONSTANTS
const TInt KBufferSize = 1024; // buffer size to store the result of
// XML parsing -> the actual buffer size
// can expand if needed (see AppendText())
//const TInt KFileBufferSize = 1024; // buffer size for file reading
//
//const TInt KOverheadLen    = 4; // length of (KOpeningTag + KClosingTag
//                                //            + KSlash + KEndOfLine)
//_LIT(KOpeningTag, "<" );
//_LIT(KClosingTag, ">" );
//_LIT(KSlash,      "/" );
//_LIT(KEndOfLine,  "\f" ); // CEikEdwin uses '\f' as EOF mark.
_LIT8( KXmlMimeType, "text/xml" );

//解析过程用的临时
static CXmlNode		*m_pTempNode;


// METHODS DEFINITION

// --------------------------------------------------------------------------
CXmlHandler* CXmlHandler::NewL (MXmlHandlerObserver& aObserver )
{
	CXmlHandler* self = CXmlHandler::NewLC (aObserver );
	CleanupStack::Pop ();
	return self;
}

// --------------------------------------------------------------------------

CXmlHandler* CXmlHandler::NewLC (MXmlHandlerObserver& aObserver )
{
	CXmlHandler* self = new (ELeave) CXmlHandler (aObserver );
	CleanupStack::PushL (self );
	self->ConstructL ();
	return self;
}

// --------------------------------------------------------------------------

CXmlHandler::~CXmlHandler ()
{
	//    Cancel();
	delete iParser;
	if(m_pXmlNode)
		delete m_pXmlNode;
	//   delete iDisplayResult;
	//  delete iBuffer;
}

// --------------------------------------------------------------------------

CXmlHandler::CXmlHandler (MXmlHandlerObserver& aObserver ) :/*CActive( EPriorityStandard ),*/
	iObserver (aObserver ), iParser (0 ),
	m_pXmlNode(NULL)
{
	
}

// --------------------------------------------------------------------------
void CXmlHandler::ConstructL ()
{
	iParser = CParser::NewL (KXmlMimeType, *this );
}

// --------------------------------------------------------------------------

void CXmlHandler::StartParsingL (const TDesC8& aFragment, TInt aSessionId )
{
	m_sessionId = aSessionId;
	m_pTempNode = NULL;
	if(m_pXmlNode)
	{
		delete m_pXmlNode;
		m_pXmlNode = NULL;
	}
	// Now, we have the whole file content in iBuffer.
	// We are ready to parse the XML content.
	iParser->ParseBeginL ();
	iParser->ParseL (aFragment );
	// Since we read the whole file contents within one-shot,
	// we can call ParseEndL() right after calling ParseL().
	iParser->ParseEndL ();
}

// --------------------------------------------------------------------------
void CXmlHandler::StartParsingL(RFs aFs, const TDesC& aFileName , TInt aSessionId)
{
	RFile rFile;
	if(KErrNone != rFile.Open( aFs, aFileName, EFileRead ))
		return;
	//内容长度
	TInt dataLen = 0;
	TInt rtn = rFile.Size(dataLen);
	if(rtn == KErrNone)
	{
		HBufC8 * data = HBufC8::NewLC(dataLen);
		TPtr8 ptr8(data->Des());
		rtn = rFile.Read(ptr8);
		if(rtn == KErrNone)
		{
#ifdef _DEBUG
//			RDebug::Printf(">>data= %s", (const char *)data->Ptr());
#endif 
			StartParsingL(data->Des(), aSessionId);
		}
		CleanupStack::PopAndDestroy();
	}
	rFile.Close();
	
}

// --------------------------------------------------------------------------

//void CXmlHandler::StartParsingWithAoL( const TDesC& aFileName )
//    {
//     // Remember to cancel any outstanding request first.
//    if ( IsActive() )
//        {
//        Cancel();
//        }
//        
//    User::LeaveIfError( iFile.Open( CCoeEnv::Static()->FsSession(), aFileName,
//        EFileRead ) );
//
//    // Create a buffer to store the file content.
//    // Note that this method uses active object to read the file.
//    // So we have to call SetActive() at the end. Then we call CParser::ParseL()
//    // in RunL() method.
//    iDisplayResult->Des().Zero();
//    delete iBuffer;
//    iBuffer = 0;
//    iBuffer = HBufC8::NewL( KFileBufferSize );
//    TPtr8 bufferPtr( iBuffer->Des() );
//    iFile.Read( bufferPtr, KFileBufferSize, iStatus );
//    SetActive();
//
//	// Tell the parser that we are about to parse a XML document.    
//    iParser->ParseBeginL();
//    }

// --------------------------------------------------------------------------

void CXmlHandler::OnStartDocumentL (const RDocumentParameters& /*aDocParam*/, TInt aErrorCode )
{
	// Display message to the screen stating that this is the starting of
	// XML document.
	//   _LIT( KOnStartDocumentL, "*** OnStartDocumentL ***\f" );
	//    AppendText( KOnStartDocumentL );

	if (KErrNone == aErrorCode )
	{
		// Do something if needed....
	}
	else
	{	
		iObserver.OnXmlNodeParseCompletedL (aErrorCode, m_pXmlNode, m_sessionId);
	}
}

// --------------------------------------------------------------------------

void CXmlHandler::OnEndDocumentL (TInt aErrorCode )
{	
#ifdef __WINSCW__
		RDebug::Printf(">>>>>XmlHandler:OnEndDocumentL->err = %d", aErrorCode);
#endif
	iObserver.OnXmlNodeParseCompletedL (aErrorCode, m_pXmlNode, m_sessionId);
}

// --------------------------------------------------------------------------
//节点起始
void CXmlHandler::OnStartElementL (const RTagInfo& aElement, const RAttributeArray& /*aAttributes*/, TInt aErrorCode )
{
	if (KErrNone == aErrorCode )
	{
#ifdef __WINSCW__
		RDebug::Printf(">>>>>XmlHandler:OnstartElement->%s", (char*)aElement.LocalName().DesC().Ptr());
#endif
		// for example: "<tag>"
		if(m_pXmlNode == NULL)
		{
			m_pXmlNode = CXmlNode::NewL(aElement.LocalName().DesC());;
			m_pTempNode = m_pXmlNode;	
		}
		else
		{
			CXmlNode *pNode = CXmlNode::NewL(aElement.LocalName().DesC());
			m_pTempNode->AddNodeL(pNode);
			m_pTempNode = pNode;
		}
	}
	else
	{
		iObserver.OnXmlNodeParseCompletedL (aErrorCode, m_pXmlNode, m_sessionId);
	}
}

// --------------------------------------------------------------------------
void CXmlHandler::OnEndElementL (const RTagInfo &aElement, TInt aErrorCode )
{
	if (KErrNone == aErrorCode )
	{
#ifdef _DEBUG
//		RDebug::Printf(">>>>>XmlHandler:OnEndElement->%s", aElement.LocalName().DesC().Ptr());
#endif
		// for example: "</tag>"
		if(m_pTempNode)
		{
		//	if(m_pTempNode->NodeName().Compare(aElement.LocalName().DesC()) == 0)
			{
				m_pTempNode = m_pTempNode->ParentNode();
			}
		}	
		/*
		if(m_pXmlNode->NodeName()->Compare(aElement.LocalName().DesC()) == 0)
		{
			iObserver.OnXmlNodeParseCompletedL (aErrorCode, m_pXmlNode, m_sessionId);
		}
		*/
	}
	else
	{
		iObserver.OnXmlNodeParseCompletedL (aErrorCode, m_pXmlNode, m_sessionId);
	}
}

// --------------------------------------------------------------------------

void CXmlHandler::OnContentL (const TDesC8 &aBytes, TInt aErrorCode )
{
	if (KErrNone == aErrorCode )
	{
//#ifdef _DEBUG
//		RDebug::Printf(">>>>>XmlHandler:OnContentL->%s", (const char *)aBytes.Ptr());
//#endif
		if(m_pTempNode)
		{
			m_pTempNode->SetNodeValueL(aBytes);
		}
	}
	else
	{
		iObserver.OnXmlNodeParseCompletedL (aErrorCode, m_pXmlNode, m_sessionId);
	}
}

// --------------------------------------------------------------------------

void CXmlHandler::OnStartPrefixMappingL (const RString& /*aPrefix*/, const RString& /*aUri*/, TInt aErrorCode )
{
	if (KErrNone == aErrorCode )
	{
		// Do something here...
	}
	else
	{
		iObserver.OnXmlNodeParseCompletedL (aErrorCode, m_pXmlNode, m_sessionId);
	}
}

// --------------------------------------------------------------------------

void CXmlHandler::OnEndPrefixMappingL (const RString& /*aPrefix*/, TInt aErrorCode )
{
	if (KErrNone == aErrorCode )
	{
		// Do something here...
	}
	else
	{
		iObserver.OnXmlNodeParseCompletedL (aErrorCode, m_pXmlNode, m_sessionId);
	}
}

// --------------------------------------------------------------------------

void CXmlHandler::OnIgnorableWhiteSpaceL (const TDesC8& /*aBytes*/, TInt aErrorCode )
{
	if (KErrNone == aErrorCode )
	{
		// Do something here...
	}
	else
	{
		iObserver.OnXmlNodeParseCompletedL (aErrorCode, m_pXmlNode, m_sessionId);
	}
}

// --------------------------------------------------------------------------

void CXmlHandler::OnSkippedEntityL (const RString& /*aName*/, TInt aErrorCode )
{
	if (KErrNone == aErrorCode )
	{
		// Do something here...
	}
	else
	{
		iObserver.OnXmlNodeParseCompletedL (aErrorCode, m_pXmlNode, m_sessionId);
	}
}

// --------------------------------------------------------------------------

void CXmlHandler::OnProcessingInstructionL (const TDesC8& /*aTarget*/, const TDesC8& /*aData*/, TInt aErrorCode )
{
	if (KErrNone == aErrorCode )
	{
		// Do something here...
	}
	else
	{
		iObserver.OnXmlNodeParseCompletedL (aErrorCode, m_pXmlNode, m_sessionId);
	}
}

// --------------------------------------------------------------------------

void CXmlHandler::OnError (TInt aErrorCode )
{
	iObserver.OnXmlNodeParseCompletedL (aErrorCode, m_pXmlNode, m_sessionId);
}

// --------------------------------------------------------------------------

TAny* CXmlHandler::GetExtendedInterface (const TInt32 /*aUid*/)
{
	return 0;
}

// --------------------------------------------------------------------------

//void CXmlHandler::AppendText( const TDesC& aText )
//    {
//    TPtr displayResultPtr( iDisplayResult->Des() );
//    if ( displayResultPtr.Length() + aText.Length() > displayResultPtr.MaxLength() )
//        {
//        iDisplayResult = iDisplayResult->ReAllocL( displayResultPtr.MaxLength()
//            + KBufferSize );
//        displayResultPtr.Set( iDisplayResult->Des() );
//        }    
//    displayResultPtr.Append( aText );
//    }
//
//// --------------------------------------------------------------------------
//
//void CXmlHandler::AppendTag( const TDesC8& aTag, TBool aIsClosingTag )
//    {
//    // Instantiate buffer to display tag information.
//    HBufC* buffer = HBufC::NewLC( aTag.Length()
//        + ( ( aIsClosingTag ) ? KOverheadLen : KOverheadLen - 1 ) );
//    TPtr bufferPtr( buffer->Des() );
//        
//    // Convert tag name from TDesC8 to TDesC16.
//    bufferPtr.Copy( aTag );
//        
//    // Add opening tag.
//    if ( aIsClosingTag )
//        {
//        bufferPtr.Insert( 0, KSlash );
//        }
//    bufferPtr.Insert( 0, KOpeningTag );
//        
//    // Add closing tag.
//    bufferPtr.Append( KClosingTag );
//    bufferPtr.Append( KEndOfLine );
//        
//    // Add to the result text and then destroy it.
//    AppendText( *buffer );
//    CleanupStack::PopAndDestroy(); // buffer
//    }

// End of File
